<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
abstract Class Base_mapper{
	
	protected $object_class = '';
	
	protected $table = '';
	
	protected $primary_key = '';

	public function __construct(){
	}
	/**
	 * __get
	 *
	 * Allows models to access CI's loaded classes using the same
	 * syntax as controllers.
	 *
	 * @param	string
	 * @access public
	 */
	public function __get($key)
	{
		$CI =& get_instance();
		return $CI->$key;
	}
	public function buildObject($row){
		$object = $this->doBuildObject($row);
		ObjectCache_helper::register($object);
		return $object;
	}
	abstract protected function doBuildObject($row);
	public function buildCollection($rows){
		$results = array();
		foreach($rows as $row){
			$result[] = $this->buildObject($row);
		}
		return $result;
	}
	/**
	 * 
	 * @param base_object $obj
	 * @return the id of the saved object
	 */
	public function save($obj){
		//remove the cache
		ObjectCache_helper::unregister($obj);
		//save it into database;
		return $this->doSave($obj);
	}
	protected function doInsert($obj){
		$obj->clearObjectStatus();
	}
	protected function doUpdate($obj){
		$obj->clearObjectStatus();
	}
	
	protected function doSave($obj){
		if($obj->isNew()){
			$this->doInsert($obj);
			return $this->db->insert_id();
		}elseif($obj->isDirty()){
			$this->doUpdate($obj);
			return $obj->getId();
		}
	} 
	public function Find($id){
		try{
			return $this->doFindInMapper($id);
		}catch (Object_not_found_in_cache_exception $e){
			return $this->doFindInDbById($id);
		}catch(Object_not_found_in_storage_exception $e){
			throw new Object_not_found_exception("Object ". $this->object_class ." with Id $id is not found");
		}
	}
	protected function doFindInMapper($id){
		if(ObjectCache_helper::hasObject($this->object_class, $id)){
			return ObjectCache_helper::getObject($this->object_class, $id);
		}
		throw new Object_not_found_in_cache_exception("Object ". $this->object_class ." with Id $id is not found in cache");
	}
	public function delete($obj){
		$this->doDelete($obj);
	}
	/**
	 * delete the item from the database, handle all the relationship in the child do method
	 * @param base_Object $obj
	 */
	protected function doDelete($obj){
		//clear the entire cache
		ObjectCache_helper::reset();
		//delete from real database
		$this->db->delete($this->table,  array('id' => $obj->getId()));
	}
	protected function doFindInDbById($id){
		$this->getBasicSelect();
		$query = $this->db->get_where($this->table, array('id'=>$id), 1);
		if($query -> num_rows() == 1)
		{
			$data = $query->result();
			return $this->buildObject($data[0]);
		}
		else
		{
			//throw object_not_found
			throw new Object_not_found_in_storage_exception("Object ". $this->object_class ." with Id $id is not found in database");
		}
	}
	/**
	 * default select for everything from db
	 */
	protected function getBasicSelect(){
		
	}	
	/**
	 * find all the items with this serach criteria
	 * @param array $condition
	 * @param int $limit
	 * @param int $offset
	 */
	public function findBySearchCriteria($condition = array(), $limit = 20, $offset = 0){
		$query = $this->db->get_where($this->table, $condition, $limit, $offset);
		return $this->buildCollection($query->result());
	}
}